#include "TutorApp2.h"

#ifdef WIN32
#ifdef Tutorial2_EXPORTS
#define TUTORAPP2_API __declspec(dllexport)
#else
#define TUTORAPP2_API __declspec(dllimport)
#endif
#else
#define TUTORAPP2_API
#endif

extern "C" TUTORAPP2_API Blobz::BaseApplication* GetInstance()
{
	Tutorial2::TutorApp2* pTutorial = new Tutorial2::TutorApp2();
	return (Blobz::BaseApplication*)pTutorial;
}

extern "C" TUTORAPP2_API unsigned int GetMajorReleaseVersion()
{
	return NUI_RELEASE_MAJOR_VER;
}

extern "C" TUTORAPP2_API unsigned int GetMinorReleaseVersion()
{
	return NUI_RELEASE_MINOR_VER;
}

extern "C" TUTORAPP2_API const char* GetAppName()
{
	return "Tutorial2";
}

namespace Tutorial2
{
	/**
	* Constructor
	*/
	TutorApp2::TutorApp2()	
	{
	}

	/**
	* Destructor
	*/
	TutorApp2::~TutorApp2()
	{
	}

	/**
	* Loads the objects in the app
	*/
	bool TutorApp2::onInitialize()
	{
		// Tell the application to use a fixed aspect ratio so that our view content is not stretched
		getWindow().setUseFixedRatio(true);
		
		mHelloMessage = "Interact with the object using standard multitouch gestures."; 

		// load the background texture
		mBackgroundTexture.load(getApplicationDirectory()+"bg.png", true);

		// Load a *.ttf font at the specified font size
		mExampleFont.loadDefaultSystemFont();
		// Set the render scale
		mExampleFont.setRenderScale(0.02f*getWindow().getWindowAspect());

		// Loads a config file
		Blobz::Config tSettings;
		tSettings.load(getApplicationDirectory()+"settings.cfg");

		// This section reads different values from the config file
		// Every read-method takes a string as a handle to the variable and it can also take
		// a default value if the value is not found in the config file as in the tFloat2 load attempt.
		int tInt = tSettings.readInt("TestInt");
		float tFloat = tSettings.readFloat("TestFloat");
		float tFloat2 = tSettings.readFloat("DoesntExist",3.1415f);
		bool tBool = tSettings.readBool("TestBool");
		QString tString = tSettings.readString("TestString");

		// The config also supports writing back values to the config file
		tSettings.writeString("TestString","Interact with the object using standard multitouch gestures");
		tSettings.writeBool("TestBool",true);
		tSettings.save(getApplicationDirectory()+"settings.cfg");
		mHelloMessage = tSettings.readString("TestString");

		// Send a message to the log
		LOG("This is test log message");

		// Send a message to the error log
		LOGERROR("This is an error message");

		// Load the Interactable
		mExampleInteractable.load(getApplicationDirectory());
		mExampleInteractable.setPosition(QVector2D(0.5f*getWindow().getWindowAspect(),0.5f));
		mExampleInteractable.setScale(0.3f);
		mExampleInteractable.setScaleLimits(0.03f, 3);

		return true;
	}

	/**
	* onReload Handler
	*/
	void TutorApp2::onReload()
	{
	}

	/**
	* Unloads the objects
	*/
	void TutorApp2::onDeinitialize()
	{
		mBackgroundTexture.unload();
		mExampleFont.unload();
		mExampleInteractable.unload();
	}

	/**
	* Triggered on every frame update
	* \param inFrameTime Time since last update ( in seconds )
	*/
	void TutorApp2::onUpdate(float inFrameTime)
	{
		// Update method, inFrameTime is in seconds since last update
		mExampleInteractable.update(inFrameTime);

		// Interactables have no information about their own shapes per default but a quick way of keeping
		// them inside the screen is to simply check if the objects position is outside of the screen and move
		// it inside if that is the case.
		if(mExampleInteractable.getPosition().x() < 0)
			mExampleInteractable.setPosX(0);
		else if(mExampleInteractable.getPosition().x() > getWindow().getWindowAspect())
			mExampleInteractable.setPosX(getWindow().getWindowAspect());
		if(mExampleInteractable.getPosition().y() < 0)
			mExampleInteractable.setPosY(0);
		else if(mExampleInteractable.getPosition().y() > 1)
			mExampleInteractable.setPosY(1);
	}

	/**
	* Render the graphics and other opengl job here
	*/
	void TutorApp2::onDraw()
	{
		// Tell Snowflake that we want to start rendering
		getWindow().enableRendering();

		// Screen setup, part of the Snowflake framework
		getWindow().defaultRenderSetup();

		// Render the background texture
		const QVector2D windowSize(getWindow().getWindowAspect(), 1.0f);
		const QVector2D mPosition(0.0f, 0.0f);

		// This segment contains a mixed part of OpenGL and basic vector math
		// Enables alpha blending
		glEnable(GL_BLEND);
		glDisable(GL_DEPTH_TEST);
		glEnable(GL_TEXTURE_2D);

		// Binds the texture ID to OpenGL so it can be used
		glBindTexture(GL_TEXTURE_2D, mBackgroundTexture.getID());
		// Begin drawing GLQuads
		glBegin(GL_QUADS);
			glColor4f(1, 1, 1, 1);
			glTexCoord2f(0,1);
			glVertex2f(mPosition.x(), mPosition.y());
			glTexCoord2f(1,1);
			glVertex2f(mPosition.x()+windowSize.x(), mPosition.y());
			glTexCoord2f(1,0);
			glVertex2f(mPosition.x()+windowSize.x(), mPosition.y()+windowSize.y());
			glTexCoord2f(0,0);
			glVertex2f(mPosition.x(), mPosition.y()+windowSize.y());
			glEnd();
		glDisable(GL_TEXTURE_2D);

		// render the title
		glDisable(GL_DEPTH_TEST);
		glColor4f(0, 0, 0, 1);

		mExampleFont.print(mHelloMessage, windowSize.x()*0.5f, 0.85f);
		
		glEnable(GL_DEPTH_TEST);

		// render the interactable
		glColor4f(1, 1, 1, 1);
		mExampleInteractable.draw();

		// Tell Snowflake that we're done rendering
		getWindow().disableRendering();
	}

	/**
	* Triggered when there is a finger down event on the screen
	* \param inData holds the touch information
	*/
	void TutorApp2::onFingerDown(const TouchListener::TouchData& inData)
	{
		if(mExampleInteractable.isInside(inData))
			mExampleInteractable.fingerDown(inData);
	}

	/**
	* Triggered when there is a finger up event on the screen
	* \param inData holds the touch information
	*/
	void TutorApp2::onFingerUp(const TouchListener::TouchData& inData)
	{
		mExampleInteractable.fingerUp(inData);
	}

	/**
	* Triggered when there is a finger update event on the screen
	* \param inData holds the touch information
	*/
	void TutorApp2::onFingerUpdate(const TouchListener::TouchData& inData)
	{
		mExampleInteractable.fingerUpdate(inData);
	}

	/**
	* Triggered when there is a finger moves out of the screen or application window
	* \param inData holds the touch information
	*/
	void TutorApp2::onFingerExit(const TouchListener::TouchData& inData)
	{
		mExampleInteractable.fingerUp(inData);
	}
}
